﻿/* Author: Prahlad Yeri
 * Created: 18-07-2012
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;

namespace libftp
{
	/// <summary>
	/// Primary interface class to use the ftp commands
	/// </summary>
	public class ftper
	{
		public bool loggingEnabled=false;

		public ftp ftpobject=new ftp();
		private System.Collections.Hashtable queue=new Hashtable();
		private bool _threadRunning=false;

		~ftper()
		{
			//make sure to clean up all variables
			ftpobject=null;
			queue=null;
		}
		
		public bool isProcessing()
		{
			return _threadRunning; //check if a thread is running for up/download
		}

		public List<ftpinfo> connect(string host, string username, string password)
		{
			return ftpobject.connect(host,username,password);
		}
		
		
		public void disconnect()
		{
			if (_threadRunning)
			{
				_threadRunning=false;
			}
			
			int timeout=60; //seconds
			DateTime start=DateTime.Now;
			while(queue.Count==0) //wait till running up/download threads complete.
			{
				if (DateTime.Now.Subtract(start).Seconds>timeout)
					break;
			}
		}

        public List<ftpinfo> browse(string path)
        {
            return ftpobject.browse(path);
        }
		
		public void addFolderToUploadQueue(string path)
		{
		}

		
		public void addFileToUploadQueue(string localFileName, string remoteDestination)
		{
			if (File.Exists(localFileName))
			{
				//uploadQ.Enqueue(localFileName);
				queue.Add(localFileName,new fileinfo(localFileName,remoteDestination, directionEnum.up));
			}
			else
			{
				throw new Exception("Incorrect file path: " + localFileName);
			}
		}
		
		public void removeFilesFromUploadQueue(string[] localFileName)
		{
			foreach(string s in localFileName)
			{
				if (queue.ContainsKey(s))
				{
					queue.Remove(s);
				}
			}
		}
		
		public void addFolderToDownloadQueue(string path)
		{
		}
		
		public void addFileToDownloadQueue(string remotefilename, string localDestination)
		{
			if (ftpobject.exists(remotefilename))
			{
				queue.Add(remotefilename,new fileinfo(remotefilename,localDestination, directionEnum.down));
			}
			else
			{
				throw new Exception("File does not exist: " + remotefilename);
			}
		}
		
		public void removeFilesFromDownloadQueue(string[] remotefilename)
		{
			foreach(string s in remotefilename)
			{
				if (queue.Contains(s))
				{
					queue.Remove(s);
				}
				else
				{
					throw new Exception("File does not exist: " + s);
				}
			}
		}
		
		//start the processing thread
		public void startProcessing()
		{
			_threadRunning=true;
			ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessQueue));
		}
		
		//stop the processing thread
		public void stopProcessing()
		{
			_threadRunning=false;
		}
		
		private void ProcessQueue(object stateInfo)
		{
			// No state object was passed to QueueUserWorkItem, so 
        	// stateInfo is null.

        	try
        	{
				while(_threadRunning && queue.Count>0)
				{
					//process next queue item
                    object[] keys = new object[queue.Keys.Count];
                    queue.Keys.CopyTo(keys, 0);
					fileinfo nextitem = (fileinfo)queue[keys[0]]; //process first item in the queue
					if (nextitem.direction== directionEnum.down)
					{
						ftpobject.download(nextitem);
					}
					else
                    {
						ftpobject.upload(nextitem);
					}
					//remove item from queue after processing it
					queue.Remove(nextitem.completeFileName);
				}
        	}
        	catch
            {
                
        	}
        	finally{
				_threadRunning=false;
        	}
		}
	}
	
	public class fileinfo
	{
		public directionEnum direction=directionEnum.down;
		public string completeFileName="";	//local or remote file name
		public string destination="";
		//public ftpinfo ftpstats=null;	//applicable only for remote files
		//public FileInfo filestats=null;	//applicable only for local files
		
		//to upload
		public fileinfo(string fileName, string destination, directionEnum direction)
		{
			this.completeFileName=fileName;
			this.destination=destination;
			this.direction= direction;
		}
	}
	
    /// <summary>
    /// Hold information about the direction of transfer i.e. upload/download
    /// </summary>
	public enum directionEnum{
		up,
		down
	}
	
	public enum directoryEntryTypes
    {
		file,
		directory
	}

	/// <summary>
	/// Hold information about the listed file/folder
	/// </summary>
	public class ftpinfo
	{
		public string filename;
	    public string path;
	    public directoryEntryTypes fileType;
	    public long size;
	    public string permission;
	    public DateTime fileDateTime;
	}

}